// ## [国内交易所行情查询](https://webapi.cninfo.com.cn/#/marketDataDate)
//
// - https://webapi.cninfo.com.cn/api/sysapi/p_sysapi1007
//   > 要随时获取：Accept-Enckey: xXUas0/cxglDt+RCws+XmA==

use serde::{ de::{ self, Visitor }, Deserialize, Deserializer, Serialize };
use std::fs::File;
use std::io::BufReader;
use std::io::Read;

use anyhow::{ ensure, Result };

#[derive(Debug, Serialize, Deserialize)]
pub struct HangQin {
    pub total: u32,
    pub records: Vec<DataItem>,
    pub resultmsg: String,
    pub count: u32,
    pub resultcode: u32,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct DataItem {
    #[serde(rename = "交易日期")]
    trade_date: String,
    #[serde(rename = "交易所")]
    exchange: String,
    #[serde(rename = "最低价")]
    low_price: f64,
    #[serde(rename = "币种")]
    currency: String,
    #[serde(rename = "涨跌")]
    change: f64,
    #[serde(rename = "最高价")]
    high_price: f64,
    #[serde(rename = "证券简称")]
    stock_name: String,
    #[serde(rename = "开盘价")]
    open_price: f64,
    #[serde(rename = "涨跌幅")]
    change_rate: f64,
    #[serde(rename = "成交金额")]
    trading_volume: f64,
    #[serde(rename = "证券代码")]
    stock_code: String,
    #[serde(rename = "成交数量")]
    deal_count: f64,
    #[serde(rename = "收盘价")]
    close_price: f64,
}

pub fn json_file(path: &str) {
    println!("\n\n****** parse json file: {}\n", path);

    // Open the JSON path and read its contents
    let path = File::open(path).expect(&format!("Failed to open path={}", path));
    let reader = BufReader::new(path);

    // Parse the JSON data into the Data struct
    let hangqing: HangQin = serde_json::from_reader(reader).expect("Failed to parse JSON");

    // Print the parsed data for demonstration
    println!("hangqing={:#?} ", hangqing);
}

/// [国内交易所行情查询](https://webapi.cninfo.com.cn/#/marketDataDate)
/// - https://webapi.cninfo.com.cn/api/sysapi/p_sysapi1007
/// > 要随时获取： [Accept-Enckey: xXUas0/cxglDt+RCws+XmA=](file:///Users/CC/gitee/conanchen/fuquants-workspace/crates/fudacli/cninfo/Accept-Enckey.png)
pub async fn hang_qing() -> Result<HangQin> {
    // POST /api/sysapi/p_sysapi1007 HTTP/1.1
    // Accept: */*
    // Accept-EncKey: xXUas0/cxglDt+RCws+XmA==
    // Accept-Encoding: gzip, deflate, br
    // Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
    // Cache-Control: no-cache
    // Connection: keep-alive
    // Content-Length: 27
    // Content-Type: application/x-www-form-urlencoded; charset=UTF-8
    // Cookie: routeId=.uc1; Hm_lvt_489bd07e99fbfc5f12cbb4145adb0a9b=1707359400; MALLSSID=3357614F4F38315333736D4D644567637341374D3455367A6C376651654E42766852473053426844566A524959686F515272536C6E4F51557976534D78795366; JSESSIONID=5BA746F203622459D0871A6B3C2C7945; SID=61ac64cb-e9d8-477a-96cb-48c034fe4059; cninfo_user_browse=603163,9900052777,%E5%9C%A3%E6%99%96%E9%9B%86%E6%88%90; Hm_lpvt_489bd07e99fbfc5f12cbb4145adb0a9b=1708249914
    // Host: webapi.cninfo.com.cn
    // Origin: https://webapi.cninfo.com.cn
    // Pragma: no-cache
    // Referer: https://webapi.cninfo.com.cn/
    // Sec-Fetch-Dest: empty
    // Sec-Fetch-Mode: cors
    // Sec-Fetch-Site: same-origin
    // User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36
    // X-Requested-With: XMLHttpRequest
    // sec-ch-ua: "Not A(Brand";v="99", "Google Chrome";v="121", "Chromium";v="121"
    // sec-ch-ua-mobile: ?0
    // sec-ch-ua-platform: "macOS"

    let request_url =
        "https://webapi.cninfo.com.cn/api/sysapi/p_sysapi1007?tdate=2024-02-07&market=SZE";
    let mut response = REQWEST_CLIENT.post(request_url)
        .header(reqwest::header::ACCEPT, "application/json, text/javascript, */*; q=0.01")
        .header("Accept-EncKey", "Rw7R2urC0Cs8MJYRIRoyIA==")
        .header("Accept-Encoding", "gzip, deflate, br")
        .header("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
        .header("Connection", "keep-alive")
        .header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
        .header("Host", "webapi.cninfo.com.cn")
        .header("Origin", "https://webapi.cninfo.com.cn")
        .header("Referer", "https://webapi.cninfo.com.cn")
        .header("Sec-Fetch-Dest", "empty")
        .header("Sec-Fetch-Mode", "cors")
        .header("Sec-Fetch-Site", "same-origin")
        .header(
            "User-Agent",
            " Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
        )
        .header("X-Requested-With", "XMLHttpRequest")
        .header(
            "sec-ch-ua",
            " \"Not A(Brand\";v=\"99\", \"Google Chrome\";v=\"121\", \"Chromium\";v=\"121\""
        )
        .header("sec-ch-ua-mobile", " ?0")
        .header("sec-ch-ua-platform", " \"macOS\"")

        .send().await?;

    let mut body = Vec::new();

    // handling Transfer-Encoding: chunked
    while let Some(chunk) = response.chunk().await.unwrap() {
        body.extend_from_slice(&chunk);
    }

    let body_str = String::from_utf8(body)?;

    // println!("*** body={}\n\nhangqin\n\n", body_str);

    let hangqing: HangQin = serde_json::from_str(&body_str)?;

    // println!("{:?}", hangqing);

    Ok(hangqing)
}

pub fn add_two_numbers(a: i32, b: i32) -> i32 {
    a + b
}

#[cfg(test)]
mod test {
    use std::{ fs::File, io::BufReader };

    use super::*;

    #[tokio::test]
    async fn test_hang_qing() {
        let client = reqwest::Client
            ::builder()
            .redirect(reqwest::redirect::Policy::limited(5)) // Follow up to 5 redirects
            .build()
            .unwrap();

        let result = hang_qing().await;
        assert_eq!(result.is_ok(), true);
        if let Ok(hang_qing) = result {
            println!("\n{:?}\n", hang_qing.records.first());
        }
    }

    #[tokio::test]
    async fn adds_two_positive_numbers() {
        let result = add_two_numbers(2, 3);
        assert_eq!(result, 5);
    }

    #[tokio::test]
    async fn adds_two_negative_numbers() {
        let result = add_two_numbers(-2, -3);
        assert_eq!(result, -5);
    }

    #[tokio::test]
    async fn adds_positive_and_negative_number() {
        let result = add_two_numbers(2, -3);
        assert_eq!(result, -1);
    }
}
